<template>
  <div class="simple-gis-map-component">
    <div :id="idName" ref="mapBox" class="map-class">
      <!-- 缩放控件自定义 -->
      <gis-zoom-control :get-zoom="getZoom" @scale="mapZoomMixin" />
    </div>
    <div v-show="mapLoading" class="layer-loading">
      <a-spin size="large" :delay="500" tip="Loading..."></a-spin>
    </div>
  </div>
</template>

<script lang="ts">
/**
 * simple gis 地图画布 - 仅作展示
 */
import { Component, Mixins, Prop } from 'vue-property-decorator'
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
import GisZoomControl from '@/components/gis/gis-analysis/GisZoomControl.vue'
import { getMapTilesByMapTypeAndStyle } from '@/components/knowledge-gis/map-packages/map-tiles'
import KGraphStore from '@/store/modules/k-graph'
import KnowledgeGisMapMixin from '@/components/knowledge-gis/knowledge-gis-map-mixin'
import './map-style.less'
import { GisInfo, DashboardLayerData } from '@/interface/k-graph-interface'

@Component({
  components: {
    GisZoomControl,
  },
})
export default class SimpleKGisMap extends Mixins(KnowledgeGisMapMixin) {
  @Prop({ type: Array, default: false }) layerList!: Array<DashboardLayerData>
  @Prop({ type: Object, default: false }) gisInfo!: GisInfo | null
  @Prop({ type: String, default: 'map' }) idName!: string

  // 返回地图当前的缩放级别
  public get getZoom() {
    return this.mapBox ? this.mapBox.getZoom() : 0
  }
  public projectId: number | null = null // 项目 id
  public nameVisible: boolean = true // 实体名称是否显示

  // 暂时使用
  public currentMapTypeStyle: any = {
    mapType: 1,
    tileStyle: 1,
  }
  // map 全局 loading
  public get mapLoading(): boolean {
    return KGraphStore.simpleMapLoading
  }

  public get gisInfoMapTypeStyle(): { mapType: number; tileStyle: number } {
    return {
      mapType: this.gisInfo?.mapType || 1,
      tileStyle: this.gisInfo?.tileStyle || 1,
    }
  }
  // 可见图层（带有排列顺序）
  public get layerIndexOrderOfVisible() {
    return this.layerList
      .filter((item: any) => item.visible === 1)
      .sort((layer1: any, layer2: any) => layer1.order - layer2.order)
  }

  public mounted() {
    this.projectId = Number(this.$route.params.id)
    this.updateMap()
  }

  /**
   * 更换地图样式
   * @param mapType 地图类型 1 - 高德
   * @param tileStyle 底图样式
   * @private
   */
  private changeMapTypeStyle(mapType: number = 1, tileStyle: number = 1) {
    this.mapBox.setStyle(getMapTilesByMapTypeAndStyle(mapType, tileStyle)) // 修改地图样式
    this.currentMapTypeStyle.mapType = mapType
    this.currentMapTypeStyle.tileStyle = tileStyle
  }

  /**
   * 更新地图
   */
  public async updateMap() {
    if (this.mapBox) {
      this.clearLayer() // 清除图层
      const { currentMapTypeStyle } = this
      // 配置 是否需要更换底图
      if (
        currentMapTypeStyle &&
        currentMapTypeStyle.tileStyle !== this.gisInfo?.tileStyle
      ) {
        this.changeMapTypeStyle(this.gisInfo?.mapType, this.gisInfo?.tileStyle)
        this.$nextTick(() => {
          this.initAddLayerOfVisible()
        })
      } else {
        this.initAddLayerOfVisible()
      }
    } else {
      this.$nextTick(() => {
        this.initMap()
        this.mapResizeMixin()
      })
    }
  }

  /**
   * 清空图层， 重新画新的图层
   */
  public clearLayer() {
    this.layerList.forEach((layer: any) => {
      const checkLayerIsExist: boolean = this.mapBox.getLayer(`${layer.id}`)
      if (checkLayerIsExist) {
        this.mapBox.removeLayer(`${layer.id}`)
        this.mapBox.removeSource(`source-${layer.id}`)
      }
    })
  }

  /**
   * 地图复位
   */
  private resetMap() {
    this.resetMapMixin(this.layerList, KGraphStore.simpleLayerData)
  }

  /**
   * 实例化地图
   */
  public async initMap() {
    KGraphStore.setSimpleMapLoading(true)
    this.initMapBoxMixin(this.gisInfo?.mapType, this.gisInfo?.tileStyle) // 实例化 mapbox gl
    this.mapBox.on('load', () => {
      this.initAddLayerOfVisible() // 初始化 加载可视状态的图层
    })
    this.addOrRemoveScaleControlMixin(true)
    this.addCoordinatesControlMixin()
    // this.addNavigationControlMixin(this.resetMap)
  }

  /**
   * 更新图层层级关系
   * visibleLayers 已显示的图层
   * includeLayerId 需要额外增加的图层
   */
  public updateMapLayerOrder(visibleLayers: any, includeLayerId?: string) {
    let needSortLayer: any[] = visibleLayers
    if (includeLayerId) {
      needSortLayer = this.layerList.filter(
        (item: any) => item.visible === 1 || item.id === includeLayerId
      )
    }
    this.$nextTick(() => {
      for (let i: number = 0; i <= needSortLayer.length - 2; i += 1) {
        const layerId1: string = `${needSortLayer[i].id}`
        const layerId2: string = `${needSortLayer[i + 1].id}`
        const layer1: any = this.mapBox.getLayer(layerId1)
        const layer2: any = this.mapBox.getLayer(layerId2)
        if (layer1 && layer2) {
          // beforeId 要在之前插入新图层的现有图层id。查看地图时， 图层将出现在图层下方 。如果省略，则图层将附加到图层数组的末尾并出现在地图上的所有其他图层之上。
          this.mapBox.moveLayer(`${layerId2}`, `${layerId1}`)
        }
      }
    })
  }

  /**
   * 检查已有 图层 是否是显示状态 添加图层
   */
  public initAddLayerOfVisible() {
    this.initAddEmpty()
    // 可视状态图层
    const visibleLayers: any[] = this.layerList.filter(
      (layer: any) => layer.visible === 1
    )
    if (visibleLayers.length > 0) {
      this.renderLayerAfterGetLayerData(visibleLayers)
      this.updateMapLayerOrder(this.layerIndexOrderOfVisible) // 调整图层层级
    }
    KGraphStore.setSimpleMapLoading(false)
  }

  /**
   * 初始化 添加空图层，占据最底层
   */
  public initAddEmpty() {
    const emptyLayerExist = this.mapBox.getLayer('base-empty-layer')
    if (!emptyLayerExist) {
      const layerInfo: any = {
        id: 'base-empty-layer',
        type: 'fill',
        source: {
          type: 'geojson',
          data: null,
        },
      }
      this.mapBox.addLayer(layerInfo)
    }
  }

  /**
   * 渲染指定多个图层（先获取数据）
   * @param layers
   */
  public async renderLayerAfterGetLayerData(layers: any[]) {
    if (layers.length > 0) {
      KGraphStore.setSimpleMapLoading(true)
      await this.getLayerDataByLayers(layers) // 获取所有可视图层的 渲染数据
      this.renderVisibleLayer(layers) // 渲染各可视状态图层
      this.resetMap() // 基于图层包围盒复位
      KGraphStore.setSimpleMapLoading(false)
    }
  }

  /**
   * 获取多个图层的渲染数据
   */
  public async getLayerDataByLayers(layers: any[]) {
    // 图层数据不存在的图层， 避免重复获取图层数据
    const dataNonExistentLayer: any[] = layers.filter((layer: any) => {
      return !KGraphStore.simpleLayerData[layer.id]
    })
    if (dataNonExistentLayer.length > 0) {
      const requests = dataNonExistentLayer.map(async (layer: any) => {
        return this.queryLayerDataByLayerId(layer.id)
      })
      await Promise.allSettled(requests)
    }
  }

  /**
   * 获取图层数据
   * @param layerId
   */
  public async queryLayerDataByLayerId(layerId: number) {
    const parameters: any = {
      projectId: this.projectId,
      layerId,
    }
    const response: any = await KGraphStore.querySimpleLayerDataById(parameters)
    return response
  }

  /**
   * 渲染所有有数据的图层
   * @private
   */
  private renderVisibleLayer(visibleLayers: any[]) {
    visibleLayers.forEach((layer: any) => {
      const beforeId: string = this.getLayerBeforeId(layer.id) // 获取图层 beforeId
      this.addLayerToMap(layer.id, layer.type, beforeId)
    })
  }

  /**
   * 获取 定位图层位置 beforeId， 用于添加图层是定位
   * @private
   */
  private getLayerBeforeId(layerId: number) {
    const visibleLayers: any[] = this.layerList.filter(
      (layer: any) => layer.visible === 1
    )
    const index: number = visibleLayers.findIndex(
      (layer: any) => layer.id === layerId
    )
    let beforeId: string | null = 'base-empty-layer'
    if (index > 0 && visibleLayers[index - 1].id) {
      const layerIdString: string = String(visibleLayers[index - 1].id)
      const beforeIdExist: boolean = !!this.mapBox.getLayer(layerIdString)
      beforeId = beforeIdExist ? layerIdString : 'base-empty-layer'
    }
    return beforeId
  }

  /**
   * 添加图层
   * @param layerId
   * @param layerType
   * @param beforeId
   */
  public addLayerToMap(layerId: number, layerType: string, beforeId: string) {
    const layerDataInfo: any = KGraphStore.simpleLayerData[layerId]
    if (!layerDataInfo) {
      return
    }
    if (layerType === 'circle') {
      this.addPointMixin(layerDataInfo, layerId, beforeId)
    } else if (layerType === 'line') {
      this.addLineMixin(layerDataInfo, layerId, beforeId)
    } else if (layerType === 'fill') {
      this.addPolygonMixin(layerDataInfo, layerId, beforeId)
    }
  }
}
</script>

<style scoped lang="less">
.simple-gis-map-component {
  height: 100%;
  position: relative;
  width: 100%;

  .map-class {
    height: 100%;
    position: relative;
    width: 100%;
  }

  .layer-loading {
    align-items: center;
    background-color: rgba(87, 96, 230, 0.1);
    display: flex;
    height: 100%;
    justify-content: center;
    left: 0;
    position: absolute;
    top: 0;
    width: 100%;
    z-index: 100;
  }
}
</style>
